<?php

namespace Sooc;

use Think\Model\RelationModel;
use Think\Page;

class Model extends RelationModel
{
    /**
     * 初始化操作
     * @name: _initialize
     * @return void
     * @author: rickeryu <lhyfe1987@163.com>
     * @time: 2018/2/23 10:53
     */
    public function _initialize() {
        defined('UID') or define('UID', is_login());
    }

    /**
     * 添加操作
     * @name: doAdd
     * @param string $data
     * @return bool|mixed
     * @author: rickeryu <lhyfe1987@163.com>
     * @time: 2018/2/23 14:45
     */
    public function doAdd($data = '') {
        $validate = $this->create($data);
        if ($validate) {
            $this->unsetCache();
            return $this->add($validate);
        }
        return false;
    }

    /**
     * 更新操作
     * @name: doUpdate
     * @param array $map
     * @param string $data
     * @return bool
     * @author: rickeryu <lhyfe1987@163.com>
     * @time: 2018/2/23 14:45
     */
    public function doUpdate($map = array(), $data = '') {
        $validate = $this->create($data, self::MODEL_UPDATE);
        if ($validate) {
            $this->unsetCache();
            return $this->where($map)->save($validate);
        }
        return false;
    }


    /**
     * 删除操作
     * @name: doDelete
     * @param array $map
     * @return bool|mixed
     * @author: rickeryu <lhyfe1987@163.com>
     * @time: 2018/2/23 14:45
     */
    public function doDelete($map = array()) {
        if ($map) {
            $this->unsetCache();
            return $this->where($map)->delete();
        }
        return false;
    }

    /**
     * 得到单条记录
     * @name: info
     * @param array $map
     * @param null $field
     * @param null $order
     * @param bool $cache
     * @param bool $master
     * @return array|mixed
     * @author: rickeryu <lhyfe1987@163.com>
     * @time: 2018/2/23 14:46
     */
    public function info($map = array(), $field = null, $order = null, $cache = false, $master = false) {

        $field = !$field ? $this->getDbFields() : $field;

        $obj = $this->where($map)->order($order)->field($field);
//        $obj->master($master);

        if ($cache) {
            $cachekey = $this->getCacheKey(array($map, $order), $field, 'info');
            $result = S($cachekey);
            if ($result === false) {
                $result = $obj->find() ?: array();
                $this->setCache($cachekey, $result);
            } else {
                $obj->select(false);
            }
            $this->SyncTableNameCache($cachekey);
            return $result;
        }
        return $obj->find();
    }

    /**
     * 得到多条记录
     * @name: lists
     * @param array $map
     * @param null $field
     * @param null $order
     * @param null $limit
     * @param null $group
     * @param bool $cache
     * @param bool $master
     * @return array|bool|mixed
     * @author: rickeryu <lhyfe1987@163.com>
     * @time: 2018/2/23 15:26
     */
    public function lists($map = array(), $field = null, $order = null, $limit = null, $group = null, $cache = false, $master = false) {
        $field = !$field ? $this->getDbFields() : $field;

        $obj = $this->where($map)->order($order)->field($field)->group($group);
//        $obj->master($master);

        if ($cache) {
            $cachekey = $this->getCacheKey(array($map, $order, $limit, $group), $field, 'lists');
            $result = S($cachekey);
            if ($result === false) {
                $result = $obj->limit($limit)->select() ?: array();
                $this->setCache($cachekey, $result);
            } else {
                $obj->limit($limit)->select(false);
            }
            $this->SyncTableNameCache($cachekey);
            return $result;
        }
        return $obj->limit($limit)->select() ?: array();
    }

    /**
     * 分页显示列表信息
     * @name: listPage
     * @param array $map
     * @param null $field
     * @param null $order
     * @param int $pagesize
     * @param bool $cache
     * @param bool $master
     * @return array|bool|mixed
     * @author: rickeryu <lhyfe1987@163.com>
     * @time: 2018/2/23 15:30
     */
    public function listPage($map = array(), $field = null, $order = null, $pagesize = 16, $cache = false, $master = false) {
        $field = !$field ? $this->getDbFields() : $field;

        $obj = $this->where($map)->order($order)->field($field);
//        $obj->master($master);

        if ($cache) {
            $cachekey = $this->getCacheKey(array($map, $order, $pagesize), $field, 'listPage');
            $result = S($cachekey);
            if ($result === false) {
                $result = $obj->findPage($pagesize) ?: array();
                $this->setCache($cachekey, $result);
            } else {
                $obj->select(false);
            }
            $this->SyncTableNameCache($cachekey);
            return $result;
        }
        return $obj->findPage($pagesize);
    }

    /**
     * 得到记录数
     * @name: doCount
     * @param array $map
     * @param bool $cache
     * @param null $order
     * @param bool $master
     * @return int|mixed
     * @author: rickeryu <lhyfe1987@163.com>
     * @time: 2018/2/23 15:34
     */
    public function doCount($map = array(), $cache = false, $master = false) {
        $obj = $this->where($map);
//        $obj->master($master);

        if ($cache) {
            $cachekey = $this->getCacheKey(array($map), 'count(*)', 'docount');
            $result = S($cachekey);
            if ($result === false) {
                $result = $obj->count() ?: 0;
                $this->setCache($cachekey, $result);
            } else {
                $obj->select(false);
            }
            $this->SyncTableNameCache($cachekey);
            return $result;
        }
        return $obj->count() ?: 0;
    }

    /**
     * 得到缓存key
     * @name: getCacheKey
     * @param $map
     * @param string $field
     * @param string $order
     * @param string $method
     * @return string
     * @author: rickeryu <lhyfe1987@163.com>
     * @time: 2018/2/23 14:27
     */
    public function getCacheKey($value = array(), $field = '', $method = '') {

        $prefix = get_pre_cache_key() . '_' . $method;
        $field = !$field ? $this->getDbFields() : $field;
        $value[] = I('request.', array());

        $model = $this->getTableName();
        $tmp = $field;
        foreach ($value as $v) {
            if ($v) {
                $tmp .= json_encode($v);
            }
        }
        return $prefix . '_' . $model . '_' . md5($tmp);
    }

    /**
     * 同步数据库表对应的缓存键值
     * @name: SyncTableNameCache
     * @return void
     * @author: RuiXinglong <ruixl@soocedu.com>
     * @time: 2017-06-19 10:00:00
     */
    public function SyncTableNameCache($key) {
        $table = $this->getTableName();
        $list = S($table) ?: array();
        if (!isset($list[$key])) {
            $list[$key] = 1;
            S($table, $list);
        }
    }

    /**
     * 设置缓存的操作
     * @name: setCache
     * @param $key
     * @param $value
     * @param null $expire
     * @return bool
     * @author: rickeryu <lhyfe1987@163.com>
     * @time: 2018/2/23 14:56
     */
    public function setCache($key, $value, $expire = null) {
        if (!is_string($key)) {
            return false;
        }
        $table = $this->getTableName();
        $list = S($table) ?: array();

        if (!in_array($key, $list)) {
            $list[$key] = 1;
            $result = S($table, $list);
        } else {
            $result = true;
        }
        if ($result) {
            S($key, $value);
        }
        return true;
    }

    /**
     * 清除缓存的操作
     * @name: unsetCache
     * @param string $key
     * @return void
     * @author: rickeryu <lhyfe1987@163.com>
     * @time: 2018/2/23 15:09
     */
    public function unsetCache($key = '') {
        $table = $this->getTableName();
        $list = S($table) ?: array();

        if ($key) {
            S($key, null);
            if (isset($list[$key])) {
                unset($list[$key]);
                S($table, $list);
            }
        } else {
            foreach ($list as $k => $v) {
                S($v, null);
            }
            S($table, null);
        }

    }


    /**
     * 查询数据
     * @access public
     * @param mixed $options 表达式参数
     * @param mixed $pageopt 分页参数
     * @return mixed
     */
    public function findPage($pageopt = false, $count = false, $options = array(), $onlyShowPage = false) {
        $REQUEST = (array)I('request.');
        // 分析表达式
        $options = $this->_parseOptions($options);
        // 如果没有传入总数，则自动根据条件进行统计
        if ($count === false) {
            // 查询总数
            $count_options = $options;
            $count_options['limit'] = 1;
            $count_options['field'] = 'count(1) as count';
            // 去掉统计时的排序提高效率
            unset($count_options['order']);
            $result = $this->db->select($count_options);
            $count = $result[0]['count'];
            unset($result);
            unset($count_options);
        }
        // 如果查询总数大于0
        if ($count > 0) {
            // 解析分页参数
            if (is_numeric($pageopt)) {
                $pagesize = intval($pageopt);
            } elseif (intval(C('LIST_NUMBERS')) > 0) {
                $pagesize = intval(C('LIST_NUMBERS'));
            } else {
                $pagesize = 10;
            }

            $p = new Page($count, $pagesize, $REQUEST);
            if ($count > $pagesize) {
//                $p->setConfig('theme','%HEADER% %FIRST% %UP_PAGE% %LINK_PAGE% %DOWN_PAGE% %END%');
                $p->setConfig('theme', '%FIRST% %UP_PAGE% %LINK_PAGE% %DOWN_PAGE% %END%');
            }
            // 查询数据
            if ($onlyShowPage == false) {
                $options['limit'] = $p->firstRow . ',' . $p->listRows;
                $resultSet = $this->select($options);

                if ($resultSet) {
                    $this->dataList = $resultSet;
                } else {
                    $resultSet = '';
                }
            }

            // 输出控制
            $output['count'] = $count;
            $output['pages'] = $p->show();
            $output['totalPages'] = $p->totalPages;
            $output['totalRows'] = $p->totalRows;
            $output['nowPage'] = $p->getNowPage();
            $output['data'] = $resultSet;
            unset($resultSet);
            unset($p);
            unset($count);
        } else {
            $output['count'] = 0;
            $output['totalPages'] = 0;
            $output['totalRows'] = 0;
            $output['nowPage'] = 1;
            $output['pages'] = '';
            $output['data'] = '';
        }
        // 输出数据
        return $output;
    }

    /**
     * 执行Sql分页处理
     * @name: findPageBySql
     * @param $sql
     * @param null $count
     * @param null $pagesize
     * @return bool
     * @author: rickeryu <lhyfe1987@163.com>
     * @time: 2018/2/23 14:06
     */
    public function findPageBySql($sql, $count = null, $pagesize = null) {
        $REQUEST = (array)I('request.');
        if (strtoupper(substr($sql, 0, 7)) !== 'SELECT ')
            return false;

        // 计算结果总数
        if (!isset($count)) {
            $count_sql = explode(' FROM ', $sql);
            if (count($count_sql) != 2) return false;
            $count_sql = 'SELECT count(*) AS count FROM ' . $count_sql[1];
            $count = $this->db->query($count_sql);
            $count = $count[0]['count'];
        }
        $count = intval($count);

        // 如果查询总数大于0
        if ($count > 0) {
            // 解析分页参数
            $pagesize = is_numeric($pagesize) ? intval($pagesize) : intval(C('LIST_NUMBERS'));
            $p = new Page($count, $pagesize, $REQUEST);
            if ($count > $pagesize) {
                $p->setConfig('theme', '%HEADER% %FIRST% %UP_PAGE% %LINK_PAGE% %DOWN_PAGE% %END%');
            }
            // 查询数据
            $limit = $p->firstRow . ',' . $p->listRows;
            $resultSet = $this->query($sql . ' LIMIT ' . $limit);
            if ($resultSet) {
                $this->dataList = $resultSet;
            } else {
                $resultSet = '';
            }
            // 输出控制
            $output['count'] = $count;
            $output['totalPages'] = $p->totalPages;
            $output['totalRows'] = $p->totalRows;
            $output['nowPage'] = $p->getNowPage();
            $output['pages'] = $p->show();
            $output['data'] = $resultSet;
            unset($resultSet);
            unset($p);
            unset($count);
        } else {
            $output['count'] = 0;
            $output['totalPages'] = 0;
            $output['totalRows'] = 0;
            $output['nowPage'] = 1;
            $output['pages'] = '';
            $output['data'] = '';
        }

        return $output;
    }

    /**
     * 执行SQL文件
     * @access public
     * @param string $file 要执行的sql文件路径
     * @param boolean $stop 遇错是否停止  默认为true
     * @param string $db_charset 数据库编码 默认为utf-8
     * @return array
     */
    public function executeSqlFile($file, $stop = true, $db_charset = 'utf-8') {
        $error = '';
        if (!is_readable($file)) {
            $error = array(
                'error_code' => 'SQL文件不可读',
                'error_sql' => '',
            );
            return $error;
        }

        $fp = fopen($file, 'rb');
        $sql = fread($fp, filesize($file));
        fclose($fp);

        $sql = str_replace("\r", "\n", str_replace('`' . 'ts_', '`' . $this->tablePrefix, $sql));

        foreach (explode(";\n", trim($sql)) as $query) {
            $query = trim($query);
            if ($query) {
                if (substr($query, 0, 12) == 'CREATE TABLE') {
                    //预处理建表语句
                    $db_charset = (strpos($db_charset, '-') === FALSE) ? $db_charset : str_replace('-', '', $db_charset);
                    $type = strtoupper(preg_replace("/^\s*CREATE TABLE\s+.+\s+\(.+?\).*(ENGINE|TYPE)\s*=\s*([a-z]+?).*$/isU", "\\2", $query));
                    $type = in_array($type, array("MYISAM", "HEAP")) ? $type : "MYISAM";
                    $_temp_query = preg_replace("/^\s*(CREATE TABLE\s+.+\s+\(.+?\)).*$/isU", "\\1", $query) .
                        (mysql_get_server_info() > "4.1" ? " ENGINE=$type DEFAULT CHARSET=$db_charset" : " TYPE=$type");

                    $res = $this->execute($_temp_query);
                } else {
                    $res = $this->execute($query);
                }
                if ($res === false) {
                    $error[] = array(
                        'error_code' => $this->getDbError(),
                        'error_sql' => $query,
                    );

                    if ($stop) return $error[0];
                }
            }
        }
        return $error;
    }
}